package com.abel.bigwater.wflow

import com.abel.bigwater.model.JsonHelper
import com.drew.imaging.ImageMetadataReader
import org.joda.time.DateTime
import org.joda.time.format.ISODateTimeFormat
import org.locationtech.jts.geom.Coordinate
import org.locationtech.jts.geom.GeometryFactory
import org.locationtech.jts.geom.Point
import org.slf4j.Logger
import java.io.InputStream
import java.util.*
import kotlin.math.abs

object LocHelper {
    /**
     * 将经纬度转换为度分秒格式
     * @param dg 116.418847
     * @return 116°25'7.85"
     */
    fun changeToDms(dg: Double): String {
        val du1 = dg.toInt()
        val tp = (dg - du1) * 60
        val minute = tp.toInt()
        val sec = String.format("%.2f", abs((tp - minute) * 60))
        return du1.toString() + "°" + abs(minute) + "'" + sec + "\""
    }

    /**
     * 度分秒转经纬度
     * @param dms 116°25'7.85"
     * @return 116.418847
     */
    fun changeToDegree(_dms: String?): Double? {
        if (_dms.isNullOrBlank()) {
            return null
        }

        val first = _dms.trim().first()
        var dms = if (first in arrayOf('N', 'S', 'E', 'W')) _dms.trim().substring(1) else _dms.trim()
        val neg = if (first in arrayOf('S', 'W')) -1 else 1
        try {
            dms = dms.replace(" ", "")
            val str2 = dms.split("°".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
            if (str2.size < 2) return 0.0
            val d = Integer.parseInt(str2[0])
            val str3 = str2[1].split("\'".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
            if (str3.size < 2) return 0.0
            val f = Integer.parseInt(str3[0])
            val str4 = str3[1].substring(0, str3[1].length - 1)
            val m = java.lang.Double.parseDouble(str4)

            val fen = f + m / 60
            var du = fen / 60 + abs(d)
            if (d < 0 || neg < 0) du = -du
            return du
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }

    const val TAG_LAT_REF = "GPS Latitude Ref"
    const val TAG_LAT = "GPS Latitude"
    const val TAG_LONG_REF = "GPS Longitude Ref"
    const val TAG_LONG = "GPS Longitude"
    const val TAG_TIME = "GPS Time-Stamp"
    const val TAG_DATE = "GPS Date Stamp"

    data class PhotoInfo(val loc: Point, val time: Date)

    /**
    GPS ~ GPS Latitude Ref: N
    GPS ~ GPS Latitude: 39° 55' 27.65"
    GPS ~ GPS Longitude Ref: E
    GPS ~ GPS Longitude: 116° 24' 7.06"
    GPS ~ GPS Altitude Ref: Sea level
    GPS ~ GPS Altitude: 49.64 metres
    GPS ~ GPS Time-Stamp: 03:52:10.000 UTC
    GPS ~ GPS Speed Ref: km/h
    GPS ~ GPS Speed: 0 km/h
    GPS ~ GPS Img Direction Ref: True direction
    GPS ~ GPS Img Direction: 88.09 degrees
    GPS ~ GPS Dest Bearing Ref: True direction
    GPS ~ GPS Dest Bearing: 88.09 degrees
    GPS ~ GPS Date Stamp: 2019:02:10
    GPS ~ GPS H Positioning Error: 50 metres
     */
    fun parseLoc(fin: InputStream?, lgr: Logger? = null): PhotoInfo? {
        fin ?: return null

        val lat = StringBuilder()
        val lng = StringBuilder()
        var dt: String? = null
        var ts: String? = null
        try {
            val md1 = ImageMetadataReader.readMetadata(fin)
            md1.directories.forEach {
                it.tags.forEach { tag ->
                    when (tag.tagName) {
                        TAG_LAT_REF -> {
                            lat.insert(0, tag.description + ' ')
                        }
                        TAG_LAT -> {
                            lat.append(tag.description)
                        }
                        TAG_LONG_REF -> {
                            lng.insert(0, tag.description + ' ')
                        }
                        TAG_LONG -> {
                            lng.append(tag.description)
                        }
                        TAG_DATE -> {
                            dt = tag.description
                        }
                        TAG_TIME -> {
                            ts = tag.description
                        }
                        else -> {
                        }
                    }
                }
            }

            lgr?.info("$lat, $lng, $dt, $ts")
            ts = if (dt.isNullOrBlank())
                DateTime.now().toString(ISODateTimeFormat.basicDate()) + 'T' + ts
            else dt!!.replace(':', '-') + 'T' + ts
            val north = changeToDegree(lat.toString())
            val east = changeToDegree(lng.toString())
            val time = JsonHelper.parseISODate(ts)

            return if (north != null && east != null && time != null)
                PhotoInfo(GeometryFactory().createPoint(Coordinate(east, north)), time)
            else null
        } catch (ex: Exception) {
            lgr?.error("fail to parse $fin", ex)
            return null
        }
    }
}